//
// Created by biu on 23-11-23.
//
#include <sys/shm.h>
#include <cerrno>
#include <cstring>

#include "ab_shm.hpp"
#include "ab_logger.hpp"
#include "ab_common.hpp"


namespace anbantech {
#define IPC_DEFAULT_PERMS 0666

    ab_shm::ab_shm() : key_(-1), size_(-1), shmid_(-1), data_(nullptr) {
//        LOG(DEBUG, "ab_shm: [%d , %d , %d , %p]", key_, size_, shmid_, data_);
    }

    ab_shm::~ab_shm() {
        // Detach the shared memory segment from the address space of the calling process
        if (data_ && shmdt(data_) == -1) {
            LOG(ERROR, "Error detaching shared memory segment");
        }
        data_ = nullptr;
        // Remove the shared memory segment (only if it was created in this process)
        if (shmctl(shmid_, IPC_RMID, nullptr) == -1) {
            LOG(ERROR, "Error removing shared memory segment");
        }
        shmid_ = -1;
    }

    int ab_shm::create(key_t key, size_t size) {
        key_ = key;
        size_ = size;
        shmid_ = shmget(key_, size_, (IPC_CREAT | IPC_EXCL) | 0666);
        if (errno == EEXIST && shmid_ < 0) {
            shmid_ = shmget(key_, 0, (0) | (IPC_DEFAULT_PERMS));
        } else if (0 != errno) {
            LOG(ERROR, "shmget(%d) failed, error info:%s", key_, strerror(errno));
            return -1;
        }
        LOG(INFO, "shm_key(%d),shm_id=%d", key_, shmid_);

        data_ = shmat(shmid_, nullptr, 0);
        if (data_ == (void *) -1) {
            LOG(ERROR, "shmat(shm_id=%d) failed, error info:%s", shmid_, strerror(errno));
            shmctl(shmid_, IPC_RMID, nullptr);
            return -1;
        }
        memset(data_,0,size_);
        LOG(DEBUG, "ab_shm create: [%d , %d , %d , %p]", key_, size_, shmid_, data_);
        return 0;
    }

    void ab_shm::write(const char *data) {
        std::strncpy(static_cast<char *>(data_), data, size_);
    }

    const char *ab_shm::read() const {
        return static_cast<const char *>(data_);
    }

    int ab_shm::id() const {
        return shmid_;
    }

} // anbantech